import { Address, toNano, fromNano, beginCell, SendMode, } from '@ton/core';
import { MyJettonMaster } from '../wrappers/MyJetton_MyJettonMaster';
import { compile, NetworkProvider } from '@ton/blueprint';
import { buildOnchainMetadata } from '../wrappers/JettonHelpers';
import { MyJettonWallet } from '../wrappers/MyJetton_MyJettonWallet';

const mainnet='https://toncenter.com/api/v2/jsonRPC';
const testnet='https://testnet.toncenter.com/api/v2/jsonRPC';
const MASTER_ADDRESS = 'EQCW2BeDLMUViUDHT8L6IHaibAIy95S7QgZg2wZdp7WmJC_Q';

const mnemonic = "miss company tell wrong door ill crunch craft caution monkey humor impose century color urge company tennis detect public clinic win equal salad mix";
const mnemonic0 = "beach earn gallery pudding comic okay pistol jar broken venture corn clap social banner bonus pyramid claim demand index dad sort cabin imitate pulp";
const mnemonic1 = "lion exact equip liberty parade fog long entry announce twenty coconut person sun fatigue february ten divert march hobby test piece catalog galaxy soda";

export async function run(provider: NetworkProvider) {
    // await deploy(provider);
    // await mint(provider);
    // await jettonBalance(provider);
    await jettonTransfer(provider);
}

export async function deploy(provider: NetworkProvider) {
    provider.network = () => "testnet";
    const senderAddress = provider.sender()?.address;
    if (!senderAddress) {
        throw new Error('Sender address is undefined.');
    }
    
    const jettonParams = {
        name: "Jetton003",
        description: "This is description of Test Jetton Token",
        symbol: "FJT003",
        image: "https://avatars.githubusercontent.com/u/104382459?s=200&v=4",
        decimals: "9",
    };
    const myJettonMaster = provider.open(
        await MyJettonMaster.fromInit(
            senderAddress,
            buildOnchainMetadata(jettonParams)
        ));

    await myJettonMaster.send(
        provider.sender(),
        {
            value: toNano('0.05'),
        },
        {
            $$type: 'Deploy',
            queryId: 0n,
        }
    );

    await provider.waitForDeploy(myJettonMaster.address);
}

export async function mint(provider: NetworkProvider) {
    const senderAddress = provider.sender()?.address;
    if (!senderAddress) {
        throw new Error('Sender address is undefined.');
    }
    const myJettonMaster = provider.open(
        MyJettonMaster.fromAddress(Address.parse(MASTER_ADDRESS)),
    );

    let mintAddress = senderAddress; // Modify this to another address if you want to mint to someone else
    let mintAmount = 1_000_000_000; // <-- ENTER THE AMOUNT OF JETTONS TO MINT

    const jettonDataBefore = await myJettonMaster.getGetJettonData();
    const supplyBefore = jettonDataBefore.total_supply;
    const nanoMint = toNano(mintAmount);

    await myJettonMaster.send(
        provider.sender(),
        {
            value: toNano('0.05'),
        },
        {
            $$type: 'JettonMint',
            origin: senderAddress,
            receiver: mintAddress,
            amount: nanoMint,
            custom_payload: beginCell().endCell(),
            forward_ton_amount: 0n,
            forward_payload: beginCell().endCell().beginParse()
        }
    );

    console.log(`Minting ${mintAmount} to ${mintAddress} and waiting 20s...`);
    await new Promise((resolve) => setTimeout(resolve, 20000));

    const jettonDataAfter = await myJettonMaster.getGetJettonData();
    const supplyAfter = jettonDataAfter.total_supply;
    if (supplyAfter == supplyBefore + nanoMint) {
        console.log('Mint successfull!\nCurrent supply:' + fromNano(supplyAfter));
    } else {
        console.log('Mint failed!');
    }
}

async function jettonBalance(provider: NetworkProvider) {
    const senderAddress = provider.sender()?.address;
    if (!senderAddress) {
        throw new Error('Sender address is undefined.');
    }
    const myJettonMaster = provider.open(
        MyJettonMaster.fromAddress(Address.parse(MASTER_ADDRESS)),
    );
    
    let jettonWalletAddress = await myJettonMaster.getGetWalletAddress(senderAddress);
    const jettonWallet = provider.open(
        MyJettonWallet.fromAddress(jettonWalletAddress),
    );
    
    let walletData = await jettonWallet.getGetWalletData();
    console.log('jetton balance:' + fromNano(walletData.balance));
}

async function jettonTransfer(provider: NetworkProvider) {
    const senderAddress = provider.sender()?.address;
    if (!senderAddress) {
        throw new Error('Sender address is undefined.');
    }
    const myJettonMaster = provider.open(
        MyJettonMaster.fromAddress(Address.parse(MASTER_ADDRESS)),
    );
    
    let jettonWalletAddress = await myJettonMaster.getGetWalletAddress(senderAddress);
    const srcWallet = provider.open(
        MyJettonWallet.fromAddress(jettonWalletAddress),
    );
    console.log('source address: '+senderAddress);
    
    const targetAddress = Address.parse('0QA93ImNS1a6b-jI1hSU48pFyFwT2y9PApB3OHSmw1nw0zC3');
    const targetJettonWalletAddress = await myJettonMaster.getGetWalletAddress(targetAddress);
    const targetJettonWallet = provider.open(
        MyJettonWallet.fromAddress(targetJettonWalletAddress),
    );
    console.log('target address: '+ targetJettonWalletAddress);
    
    const walletDataBefore = await targetJettonWallet.getGetWalletData();
    const balanceBefore = walletDataBefore.balance;
    console.log('Current balance:' + fromNano(balanceBefore));

    const transAmount = 1; // <-- ENTER THE AMOUNT OF JETTONS TO TRANSFER
    const nanoTransfer = toNano(transAmount);
    const comment = "hello 1";
    const payload = beginCell() 
        .storeBit(1)
        .storeRef(
            beginCell()
                .storeUint(0, 32)
                .storeStringTail(comment)
            .endCell()
        ).endCell()
        .beginParse()
        ;

    await srcWallet.send(
        provider.sender(),
        {
            value: toNano('0.05'),
            // sendMode: SendMode.PAY_GAS_SEPARATELY,
        },
        {
            $$type: 'JettonTransfer',
            query_id: 101n,
            destination: targetAddress,
            response_destination: senderAddress,
            amount: nanoTransfer,
            custom_payload: beginCell().endCell(),
            forward_ton_amount: 0n,
            forward_payload: payload,
        }
    );

    console.log(`Transfer ${transAmount} to ${targetAddress} and waiting 22s...`);
    await new Promise((resolve) => setTimeout(resolve, 22000));

    const walletDataAfter = await targetJettonWallet.getGetWalletData();
    const balanceAfter = walletDataAfter.balance;
    console.log('Current balance:' + fromNano(balanceAfter));
}